package dcutils.rpg.currency;

// Import Java JDK Classes
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * A currency object wraps an integer.<br/>
 * This integer is the overall value (total) of the currency.<br/>
 * It can be defined by another integer, Quantities, or Units.<br/>
 * It is divisible by Units, as to express it in readable terms.<br/>
 * Example usage:
<pre style='color:#d1d1d1;background:#000000;'>
<span style='color:#bb7977; font-weight:bold; '>Currency</span> c = new <span style='color:#bb7977; font-weight:bold; '>Currency</span>(
   <span style='color:#bb7977; font-weight:bold; '>Quantity</span>.getQuantity(<span style='color:#bb7977; font-weight:bold; '>Unit</span>.SILVER, 10),
   <span style='color:#bb7977; font-weight:bold; '>Quantity</span>.getQuantity(<span style='color:#bb7977; font-weight:bold; '>Unit</span>.GOLD, 15),
   <span style='color:#bb7977; font-weight:bold; '>Quantity</span>.getQuantity(<span style='color:#bb7977; font-weight:bold; '>Unit</span>.COPPER, 5)
)<span style='color:#d2cd86; '>;</span>

System.out.println(c)<span style='color:#d2cd86; '>;</span> <span style='color:#9999a9; '>&#47;* PRINTS</span>
<span style='color:#9999a9; '>Gold (15)</span>
<span style='color:#9999a9; '>Silver (10)</span>
<span style='color:#9999a9; '>Copper (5)</span>
<span style='color:#9999a9; '>*&#47;</span>

System.out.println(c.getBaseValue())<span style='color:#d2cd86; '>;</span> <span style='color:#9999a9; '>&#47;* PRINTS</span>
<span style='color:#9999a9; '>151005</span>
<span style='color:#9999a9; '>*&#47;</span>

c.add(<span style='color:#bb7977; font-weight:bold; '>Quantity</span>.getQuantity(<span style='color:#bb7977; font-weight:bold; '>Unit</span>.SILVER, 95))<span style='color:#d2cd86; '>;</span>
System.out.println(c)<span style='color:#d2cd86; '>;</span> <span style='color:#9999a9; '>&#47;* PRINTS</span>
<span style='color:#9999a9; '>Gold (16)</span>
<span style='color:#9999a9; '>Silver (5)</span>
<span style='color:#9999a9; '>Copper (5)</span>
<span style='color:#9999a9; '>*&#47;</span>

System.out.println(c.getBaseValue())<span style='color:#d2cd86; '>;</span> <span style='color:#9999a9; '>&#47;* PRINTS</span>
<span style='color:#9999a9; '>160505</span>
<span style='color:#9999a9; '>*&#47;</span>
</pre>
 * @see Quantity
 * @see Unit
 * @author dca
 */
public class Currency {
   /** The value of the currency.  All added currencies and quantities get added to this single value.<br/> */
   private int baseValue;

   /**
    * The constructor initializes the base value of this currency
    * with the supplied integer value.<br/>
    * @param value The supplied integer value.<br/>
    */
   public Currency(int value) {
      setBaseValue(value);
   } // END constructor

   /**
    * The constructor initializes the base value of this currency
    * with the supplied array of quantities.<br/>
    * @param quantities The supplied array of quantities.<br/>
    */
   public Currency(Quantity ... quantities) {
      if(null != quantities) {
         for(Quantity quantity : quantities) {
            add(quantity);
         } // END loop
      } // END if
   } // END constructor

   /**
    * The copy constructor initializes the base value of this currency
    * with the supplied currency.<br/> 
    * @param currency The supplied currency.<br/>
    */
   public Currency(Currency currency) {
      if(null != currency) {
         add(currency);
      } // END if
   } // END constructor

   /**
    * The getter for the base value of the currency.<br/>
    * @return baseValue The base value of the currency.<br/>
    */
   public int getBaseValue() {
      return baseValue;
   } // END getBaseValue

   /**
    * The setter for the base value of the currency.<br/>
    * @param value The value to set to the base value of the currency.<br/>
    */
   public void setBaseValue(int value) {
      baseValue = value;
   } // END setBaseValue

   /**
    * Adds the supplied quantity to the base value of the currency.<br/>
    * @param quantity The supplied quantity.<br/>
    */
   public void add(Quantity quantity) {
      if(null != quantity) {
         baseValue += quantity.getBaseValue();
      } // END if
   } // END add

   /**
    * Adds the supplied currency to the base value of this currency.<br/>
    * @param currency The supplied currency.<br/>
    */
   public void add(Currency currency) {
      if(null != currency) {
         baseValue += currency.getBaseValue();
      } // END if
   } // END add

   /**
    * Subtracts the supplied quantity from the base value of the currency.<br/>
    * This only happens if the base value was greater than or equal to that of the supplied quantity.<br/>
    * @param quantity The supplied quantity.<br/>
    * @return True if the base value was greater than or equal to that of the supplied quantity; false otherwise.<br/>
    */
   public boolean subtract(Quantity quantity) {
      if(canAfford(quantity)) {
         if(null != quantity) {
            baseValue -= quantity.getBaseValue();
         } // END if
         return true;
      } else {
         return false;
      } // END if/else
   } // END subtract

   /**
    * Subtracts the supplied currency from the base value of this currency.<br/>
    * This only happens if the base value was greater than or equal to that of the supplied currency.<br/>
    * @param currency The supplied currency.<br/>
    * @return True if the base value was greater than or equal to that of the supplied currency; false otherwise.<br/>
    */
   public boolean subtract(Currency currency) {
      if(canAfford(currency)) {
         if(null != currency) {
            baseValue -= currency.getBaseValue();
         } // END if
         return true;
      } else {
         return false;
      } // END if/else
   } // END subtract

   /**
    * Determines if the base value is greater than or equal to that of the supplied quantity.<br/>
    * @param cost The supplied quantity.<br/>
    * @return True if the base value is greater than or equal to that of the supplied quantity; false otherwise.<br/>
    */
   public boolean canAfford(Quantity cost) {
      if(null != cost) {
         return baseValue >= cost.getBaseValue();
      } else {
         return true;
      } // END if/else
   } // END canAfford

   /**
    * Determines if the base value is greater than or equal to that of the supplied currency.<br/>
    * @param cost The supplied currency.<br/>
    * @return True if the base value is greater than or equal to that of the supplied currency; false otherwise.<br/>
    */
   public boolean canAfford(Currency cost) {
      if(null != cost) {
         return baseValue >= cost.getBaseValue();
      } else {
         return true;
      } // END if/else
   } // END canAfford

   /**
    * Returns a string representation of this currency, specified in terms of highest-order quantities.<br/>
    * @return String A string representation of this currency.<br/>
    */
   @Override
   public String toString() {
      final StringBuffer buffer = new StringBuffer(512);
      final List<Unit> units = Arrays.asList(Unit.values());
      int tempValue = baseValue;

      Collections.reverse(units); // highest to lowest

      for(Unit unit : units) {
         if(tempValue >= unit.getBaseValue() || !buffer.toString().isEmpty()) {
            int amt = tempValue / unit.getBaseValue();
            int rem = tempValue % unit.getBaseValue();

            if(!buffer.toString().isEmpty()) buffer.append(String.format("%n"));

            buffer.append(new Quantity(unit, amt));
            tempValue = rem;
         } // END if
      } // END loop

      return buffer.toString();
   } // END toString

   /**
    * Decides if an object is equal to this currency.<br/>
    * In order for an object to be equal to this currency:<br/>
    * the object must also be a currency, must not be null, and its baseValue must be equal to this baseValue.<br/>
    * @param obj The item to check for value equality.<br/>
    * @return True or false<br/>
    */
   @Override
   public boolean equals(Object obj) {
      if(null == obj) {
         return false;
      } else if(obj instanceof Currency) {
         Currency currency = (Currency)obj;

         return this.getBaseValue() == currency.getBaseValue();
      } else {
         return false;
      } // END if/else
   } // END equals

   /**
    * Creates a hash code for this currency.<br/>
    * The hash code uses prime numbers and the baseValue.<br/>
    * @return integer The hash code.<br/>
    */
   @Override
   public int hashCode() {
      int hashCode = 101;
      hashCode = (11 * hashCode) + baseValue;
      return hashCode;
   } // END hashCode
} // END class Currency
